/* 
 * Autores:
 *      Jonathan Lopez  11106
 *      Jorge Martínez  11237
 * 
 * Archivo: Contenedor.java
 * Última Revision: $Rev: 69 $
 *      Fecha: $Date: 2011-09-19 06:58:38 +0000 (Mon, 19 Sep 2011) $
 */ 

package Manejo.Transporte;

import Archivador.Informador;
import Archivador.Util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;

import Manejo.Transporte.Registros.*;
import Archivador.iArchivable;

/**
 * Representa un contenedor con Producto
 * 
 * @author Jonathan López
 * @author Jorge Martinez
 */
public class Contenedor implements iArchivable
{
    private ArrayList<Evento> eventos;
    private double peso;
    private ArrayList<Producto> contenido;
    
    private ID puertoDestino;
    private String propietario;
    
    private final Registros registros;
    
    /**
     * Inicializa el contenedor para poder introducir los datos necesarios
     * @param contenido 
     * @param puertoDestino
     * @param propietario  
     */
    public Contenedor( Producto[] contenido, ID puertoDestino,
            String propietario, Registros registros )
    {
        this.puertoDestino = puertoDestino;
        this.propietario = propietario;
        this.registros = registros;
        
        eventos= new ArrayList<Evento>();
        
        
        this.contenido= new ArrayList<Producto>();
        this.contenido.addAll( Arrays.asList(contenido) );
        
        peso = 0;
        for( Producto p: contenido )
            peso += p.obtenerPeso();
    }
    
    /**
     * Añade un nuevo evento de atraco a un Puerto con una estampa de tiempo.
     * El evento únicamente marca cuando un Contenedor en un Barco atraca en
     * un puerto específico.
     * @param idPuerto Puerto en el que atraca el Barco que contiene el
     * Contenedor
     * @param fecha estampa de tiempo del evento
     */
    public void agregarEvento( ID idPuerto, Date fecha ){
        eventos.add( new Evento(idPuerto, fecha, registros ) );
    }

    /**
     * Regresa un arreglo de Producto que representa los contenidos 
     * consolidados dentro del Contenedor.
     * @return arreglo de Producto
     */
    public Producto[] obtenerContenido()
    {
        return contenido.toArray( new Producto[0] );
    }

    /**
     * Regresa un arreglo con todos los Eventos registrados para el Contenedor.
     * @return arreglo de Eventos
     */
    public Evento[] obtenerEventos()
    {
        return eventos.toArray( new Evento[0] );
    }

    /**
     * Devuelve el peso, en Toneladas métricas, del Contenedor en base a los
     * productos que se consolidaron en él.
     * @return peso total, en Toneladas métricas
     */
    public double obtenerPeso()
    {
        return peso;
    }

    /**
     * Devuelve el nombre del propietario del Contenedor.
     * @return String con nombre del propietario
     */
    public String obtenerPropietario()
    {
        return propietario;
    }

    /**
     * Devuelve el ID del puerto al que se dirige el Contenedor
     * @return idPuerto destino
     */
    public ID obtenerPuertoDestino()
    {
        return puertoDestino;
    }

    /**
     * Devuelve una representación String del objeto que contiene información
     * de Eventos, Peso, Contenido, PuertoDestino y Propietario.
     * @return Representación String del objeto
     */
    @Override
    public String toString()
    {
        RegPuertos registroPuertos = registros.obtenerRegistroPuertos();
        
        return "Contenedor{" + "peso=" + peso +
                ", contenido=" + contenido +
                ", puertoDestino=" + registroPuertos.obtenerNombre(puertoDestino) +
                ", propietario=" + propietario + '}';
    }
    
    
    
    /**
     * Regresa un línea de texto para ser guardada en un medio persistente.
     * @return String
     * @see iArchivable#guardar() 
     */
    @Override
    public String guardar()
    {
        // Orden: propietario, puertoDestino, contenido, eventos
        String linea = "[";
        linea += propietario + separador;
        linea += puertoDestino.guardar() + separador;
        
        linea += "CONTENIDO" + separador;
        for( Producto p: contenido )
            linea += p.guardar() + separador;
        
        linea += "EVENTOS" + separador;
        for( Evento e: eventos )
            linea += e.guardar() + separador;
        
        linea += "]";
        
        return linea;
    }
    
    /**
     * Genera un nuevo Contenedor a partir de una línea de texto creada
     * a través del método guardar()
     * @param linea
     * @return nuevo Contenedor con los datos leídos desde la línea dada,
     * o null si no se pudo interpretar la línea.
     */
    public static Contenedor parseContenedor( String linea, Registros registros ){
        // Validar linea
        if( !Util.validarLinea(linea) )
            return null;
        
        // Eliminar corchetes
        String srContenedor = Util.eliminarExtremos(linea);
        if( srContenedor.equals("") )
            return null;
        
        // Partir los elementos
        String[] partes = srContenedor.split( separador );
        int minimoPartes = 4;
        if( partes.length < minimoPartes )
            return null;
        
        // Parsear cada elemento
        // Orden: peso, propietario, puertoDestino, contenido, eventos
        String _propietario = "";
        ID _puertoDestino = ID.idNulo;
        ArrayList<Producto> _contenido = new ArrayList<Producto>();
        ArrayList<Evento> _eventos = new ArrayList<Evento>();
        boolean procesarContenido = true;
        
        for (int n = 0; n != partes.length; n++) {
            if( n == 0 )
                _propietario = partes[n];
            else if( n == 1 )
                _puertoDestino = ID.parseID(partes[n]);
            else{
                // Ignorar String vacios
                if( partes[n].equals("") )
                    continue;
                
                // Ver si hay que procesar contenido o eventos
                if( partes[n].equals( "CONTENIDO" ) ){
                    procesarContenido = true;
                    continue;
                } else if( partes[n].equals( "EVENTOS" ) ){
                    procesarContenido = false;
                    continue;
                }
                
                // Procesar cada elemento
                if( procesarContenido )
                    _contenido.add( Producto.parseProducto(partes[n] ) );
                else
                    _eventos.add( Evento.parseEvento( partes[n], registros ) );
            }
                        
        }
        
        // Crear el nuevo objeto
        Contenedor nuevoContenedor = new Contenedor( 
                _contenido.toArray(new Producto[0] ),
                _puertoDestino, _propietario,
                registros );
        nuevoContenedor.eventos = _eventos;
        
        return nuevoContenedor;
    }
    
    /**
     * Punto de entrada para las pruebas unitarias de Contenedor.
     * @param args
     */
    public static void main( String[] args ){
        int pruebas = 10;
        int fallos = 0;
        java.util.Random generador = new java.util.Random();
        Registros registros = new Registros();
        
        RegContenedores registroContenedores = registros.obtenerRegistroContenedores();
        
        for (int n = 0; n != pruebas; n++) {
            // Inicializar los productos que se llevará
            Producto[] productos = new Producto[10];
            for (int i = 0; i != productos.length; i++)
                productos[i] = new Producto( generador.nextDouble(), "Salmón" );
            
            
            // Crear los contenedores
            Contenedor contenedor = new Contenedor( productos,
                    GeneradorID.nuevoID(), "Marco Aurelio Gaudí",
                    registros );
            /* Agregar eventos */
            int nEventos = generador.nextInt( 5 );
            for (int i = 0; i != nEventos; i++)
                contenedor.agregarEvento( GeneradorID.nuevoID(),
                        new Date(generador.nextLong() ) );
            
            String linea = contenedor.guardar();
            Contenedor nuevoContenedor = Contenedor.parseContenedor(linea,
                    registros);
            
            boolean iguales = contenedor.toString().equals(nuevoContenedor.toString());
            if( !iguales )
                ++fallos;
            
            System.out.println( linea + " & " + iguales );
            System.out.println("\t" + contenedor );
            System.out.println("\t" + nuevoContenedor );
            
            // Agrega el Contenedor al registro
            registroContenedores.agregarContenedor( contenedor );
        }
        System.out.println("FALLOS: " + fallos );
        
        registroContenedores.guardarTodo();
        Informador.guardarCambios();
    }
}
